package scatter.schedulequartz.rest.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import scatter.common.rest.exception.BusinessDataNotFoundException;
import scatter.schedulequartz.pojo.form.*;
import scatter.schedulequartz.pojo.vo.JobDetailExtVo;
import scatter.schedulequartz.pojo.vo.JobDetailVo;
import scatter.schedulequartz.pojo.vo.TriggerVo;
import scatter.schedulequartz.rest.ScheduleQuartzConfiguration;
import scatter.schedulequartz.rest.job.HttpInvokerJob;
import scatter.schedulequartz.rest.job.SpringBeanInvokerJob;
import scatter.schedulequartz.rest.mapstruct.ScheduleMapStruct;
import scatter.schedulequartz.rest.service.IQuartzJobService;
import scatter.schedulequartz.rest.tools.ScheduleTool;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * Created by yangwei
 * Created at 2021/2/2 18:18
 */
@RestController
@RequestMapping(ScheduleQuartzConfiguration.CONTROLLER_BASE_PATH + "/schedule/job")
@Api(tags = "任务计划相关接口")
public class ScheduleJobController extends ScheduleBaseController {

    @Autowired
    private IQuartzJobService iQuartzJobService;
    @Autowired
    private ScheduleMapStruct scheduleMapStruct;


    @ApiOperation("添加任务")
    @PreAuthorize("hasAuthority('schedule:job:add')")
    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public JobDetailVo add(@RequestBody @Valid JobCronAddForm addForm) throws SchedulerException, ClassNotFoundException {
        Scheduler scheduler = getUniqueScheduler(scheduleMapStruct.map(addForm));
        boolean b = iQuartzJobService.addJob(addForm, scheduler);
        return scheduleMapStruct.mapJobDetail(scheduler.getJobDetail(JobKey.jobKey(addForm.getName(), addForm.getGroup())));
    }

    @ApiOperation("复制任务")
    @PreAuthorize("hasAuthority('schedule:job:copy')")
    @PostMapping("/copy")
    @ResponseStatus(HttpStatus.CREATED)
    public Boolean copyJob(@RequestBody @Valid NameAndGroupForm nameAndGroupForm,@RequestBody @Valid ScheduleQueryForm scheduleQueryForm) throws SchedulerException, ClassNotFoundException {
        Scheduler scheduler = getUniqueScheduler(scheduleMapStruct.map(scheduleQueryForm));
        boolean b = iQuartzJobService.copyJob(nameAndGroupForm, scheduler);
        return b;
    }

    @ApiOperation("更新任务")
    @PreAuthorize("hasAuthority('schedule:job:update')")
    @PutMapping
    @ResponseStatus(HttpStatus.CREATED)
    public JobDetailVo add(@RequestBody @Valid JobCronUpdateForm updateForm,ScheduleQueryForm scheduleQueryForm) throws SchedulerException, ClassNotFoundException {
        Scheduler scheduler = getUniqueScheduler(scheduleMapStruct.map(scheduleQueryForm));
        boolean b = iQuartzJobService.updateJob(updateForm, scheduler);
        return scheduleMapStruct.mapJobDetail(scheduler.getJobDetail(JobKey.jobKey(updateForm.getName(), updateForm.getGroup())));
    }

    @ApiOperation("删除任务")
    @PreAuthorize("hasAuthority('schedule:job:delete')")
    @DeleteMapping
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public Boolean delete(@RequestBody @Valid NameAndGroupForm addForm,ScheduleQueryForm scheduleQueryForm) throws SchedulerException, ClassNotFoundException {
        List<Scheduler> schedules = iQuartzJobService.schedules(scheduleQueryForm);
        for (Scheduler schedule : schedules) {
            if (schedule.checkExists(JobKey.jobKey(addForm.getName(),addForm.getGroup()))) {
                iQuartzJobService.deleteJob(addForm, schedule);
            }
        }
        return true;
    }
    @ApiOperation("暂停任务")
    @PreAuthorize("hasAuthority('schedule:job:pause')")
    @PostMapping("/pause")
    @ResponseStatus(HttpStatus.OK)
    public Boolean pause(@RequestBody @Valid NameAndGroupForm addForm,ScheduleQueryForm scheduleQueryForm) throws SchedulerException, ClassNotFoundException {
        List<Scheduler> schedules = iQuartzJobService.schedules(scheduleQueryForm);
        for (Scheduler schedule : schedules) {
            if (schedule.checkExists(JobKey.jobKey(addForm.getName(),addForm.getGroup()))) {
                iQuartzJobService.pauseJob(addForm, schedule);
            }
        }
        return true;
    }
    @ApiOperation("恢复任务")
    @PreAuthorize("hasAuthority('schedule:job:resume')")
    @PostMapping("/resume")
    @ResponseStatus(HttpStatus.OK)
    public Boolean resume(@RequestBody @Valid NameAndGroupForm addForm,ScheduleQueryForm scheduleQueryForm) throws SchedulerException, ClassNotFoundException {
        List<Scheduler> schedules = iQuartzJobService.schedules(scheduleQueryForm);
        for (Scheduler schedule : schedules) {
            if (schedule.checkExists(JobKey.jobKey(addForm.getName(),addForm.getGroup()))) {
                iQuartzJobService.resumeJob(addForm, schedule);
            }
        }
        return true;
    }

    @ApiOperation("获取任务")
    @PreAuthorize("hasAuthority('schedule:job:get')")
    @GetMapping
    @ResponseStatus(HttpStatus.OK)
    public JobDetailExtVo get(@Valid NameAndGroupForm addForm, ScheduleQueryForm scheduleQueryForm) throws SchedulerException, ClassNotFoundException {
        Scheduler scheduler = getUniqueScheduler(scheduleMapStruct.map(scheduleQueryForm));
        JobQueryForm jobQueryForm = new JobQueryForm();
        jobQueryForm.setName(addForm.getName());
        jobQueryForm.setGroup(addForm.getGroup());
        List<JobDetailVo> jobs = iQuartzJobService.getJobs(jobQueryForm, scheduler);
        TriggerQueryForm triggerQueryForm = new TriggerQueryForm();
        triggerQueryForm.setName(addForm.getName());
        triggerQueryForm.setGroup(addForm.getGroup());
        List<TriggerVo> triggers = iQuartzJobService.getTriggers(triggerQueryForm, scheduler);
        ScheduleTool.assertJobExistAndUnique(jobs);
        ScheduleTool.assertTriggerExistAndUnique(triggers);
        // 添加额外信息
        JobDetailExtVo jobDetailExtVo = scheduleMapStruct.map(jobs.stream().findFirst().get());
        jobDetailExtVo.setCronExpression(triggers.iterator().next().getCronExpression());
        if (HttpInvokerJob.class.getName().equals(jobDetailExtVo.getJobClassName())) {
            jobDetailExtVo.setJobClassType(JobCronAddForm.JOB_CLASS_TYPE_HTTP);
        }else if (SpringBeanInvokerJob.class.getName().equals(jobDetailExtVo.getJobClassName())) {
            jobDetailExtVo.setJobClassType(JobCronAddForm.JOB_CLASS_TYPE_BEAN);
        }else {
            jobDetailExtVo.setJobClassType(JobCronAddForm.JOB_CLASS_TYPE_CUSTOM);
        }
        // 额外参数信息
        if (jobDetailExtVo.getDataMap() != null) {

            jobDetailExtVo.setHttpUrl((String) jobDetailExtVo.getDataMap().get(HttpInvokerJob.HttpInvokerJobDataMapKeys.httpUrl.name()));
            jobDetailExtVo.setHttpMethod((String) jobDetailExtVo.getDataMap().get(HttpInvokerJob.HttpInvokerJobDataMapKeys.httpMethod.name()));
            jobDetailExtVo.setHttpHeaders((Map<String, String>) jobDetailExtVo.getDataMap().get(HttpInvokerJob.HttpInvokerJobDataMapKeys.httpHeaders.name()));
            jobDetailExtVo.setHttpParams((Map<String, Object>) jobDetailExtVo.getDataMap().get(HttpInvokerJob.HttpInvokerJobDataMapKeys.httpParams.name()));

            jobDetailExtVo.setBeanName((String) jobDetailExtVo.getDataMap().get(SpringBeanInvokerJob.SpringBeanInvokerJobDataMapKeys.beanName.name()));
            jobDetailExtVo.setBeanMethodName((String) jobDetailExtVo.getDataMap().get(SpringBeanInvokerJob.SpringBeanInvokerJobDataMapKeys.beanMethodName.name()));
            jobDetailExtVo.setBeanMethodParams((List) jobDetailExtVo.getDataMap().get(SpringBeanInvokerJob.SpringBeanInvokerJobDataMapKeys.beanMethodParams.name()));

            Arrays.stream(HttpInvokerJob.HttpInvokerJobDataMapKeys.values()).forEach(item-> jobDetailExtVo.getDataMap().remove(item.name()));
            Arrays.stream(SpringBeanInvokerJob.SpringBeanInvokerJobDataMapKeys.values()).forEach(item-> jobDetailExtVo.getDataMap().remove(item.name()));
        }
        return jobDetailExtVo;
    }

    @ApiOperation("不分页查询任务")
    @PreAuthorize("hasAuthority('schedule:getJobList')")
    @GetMapping("/getJobList")
    @ResponseStatus(HttpStatus.OK)
    public List<JobDetailVo> getJobList(JobQueryForm jobQueryForm,ScheduleQueryForm scheduleQueryForm) throws SchedulerException {
        List<Scheduler> schedules = iQuartzJobService.schedules(scheduleQueryForm);
        List<JobDetailVo> result = new ArrayList<>();
        for (Scheduler schedule : schedules) {
            List<JobDetailVo> jobs = iQuartzJobService.getJobs(jobQueryForm, schedule);
            if (!isEmpty(jobs)) {
                result.addAll(jobs);
            }
        }
        if (isEmpty(result)) {
            throw new BusinessDataNotFoundException("暂无数据");
        }
        return result;
    }

    @ApiOperation("执行一次任务")
    @PreAuthorize("hasAuthority('schedule:job:executeOnce')")
    @PostMapping("/executeOnce")
    @ResponseStatus(HttpStatus.CREATED)
    public Boolean executeOnce(@RequestBody @Valid NameAndGroupForm nameAndGroupForm,@RequestBody @Valid ScheduleForm scheduleForm) throws SchedulerException, ClassNotFoundException {
        Scheduler scheduler = getUniqueScheduler(scheduleForm);
        boolean b = iQuartzJobService.executeOnce(nameAndGroupForm, scheduler);
        return b;
    }
}
